home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Hot Mix 17
/
Hot Mix 17.iso
/
HM17_SGI
/
research
/
examples
/
demo
/
demosrc
/
d_morph.pro
< prev
next >
Wrap
Text File
|
1997-07-08
|
16KB
|
495 lines
; $Id: d_morph.pro,v 1.8 1997/04/22 21:10:53 dave Exp $
;
; Copyright (c) 1997, Research Systems, Inc. All rights reserved.
; Unauthorized reproduction prohibited.
;
;+
; FILE:
; d_morph.pro
;
; CALLING SEQUENCE: d_morph
;
; PURPOSE:
; Morph 2 images.
;
; MAJOR TOPICS: Visualization and data analysis
;
; CATEGORY:
; IDL 5.0
;
; INTERNAL FUNCTIONS and PROCEDURES:
; fun barycentric - Compute the barycentric matrix.
; pro morph - Compute the morhing imges
; pro morph_demo_event - Event handler
; pro morphCleanup - Cleanup
; pro d_morph - Main procedure
;
; EXTERNAL FUNCTIONS, PROCEDURES, and FILES:
;
; NONE
;
; REFERENCE: IDL Reference Guide, IDL User's Guide
;
; NAMED STRUCTURES:
; none.
;
; COMMON BLOCS:
; morph_demo_common
;
; MODifICATION HISTORY:
; DS - Written.
;-
forward_function people_image
;----------------------------------------------------------------------------
;
; Purpose: Compute and returns the barycentric matrix.
;
function barycentric, $
x, $
y, $
xt, $
yt, $
zt
det = (xt(1)-xt(0)) * (yt(2)-yt(0)) - (xt(2)-xt(0)) * (yt(1)-yt(0))
w0 = ((xt(1)-x) * (yt(2)-y) - (xt(2)-x) * (yt(1)-y)) / det
w1 = ((xt(2)-x) * (yt(0)-y) - (xt(0)-x) * (yt(2)-y)) / det
w2 = ((xt(0)-x) * (yt(1)-y) - (xt(1)-x) * (yt(0)-y)) / det
PRINT, w0, w1, w2
RETURN,w0 * zt(0) + w1 * zt(1) + w2 * zt(2)
end
;----------------------------------------------------------------------------
;
; Purpose: This procedure actually does the morphing.
;
pro morph, $
i0, $ ; IN: first image
i1, $ ; IN: seconsd image
x0, $ ; IN: x control point of first image
y0, $ ; IN: y control point of first image
x1, $ ; IN: x control point of second image
y1, $ ; IN: y control point of second image
nsteps, $ ; IN: number of transitions, including the 2 end images
QUINTIC = quint ; IN: (opt) indicates quintic interpolation.
ncp = N_ELEMENTS(x0)
if ( (ncp NE N_ELEMENTS(y0)) OR (ncp NE N_ELEMENTS(x1)) OR $
(ncp NE N_ELEMENTS(y1)) ) then $
MESSAGE, "Number of control points doesn't match"
TRIANGULATE, x0, y0, tr, bounds
TRIANGULATE, x1, y1, tr1, bounds1
s = SIZE(i0)
t = SIZE(i1)
if (s(0) NE 2) OR (t(0) NE 2) OR (s(1) NE t(1)) OR (s(2) NE t(2)) then $
MESSAGE,'Image dimensions inconsistent'
nx = s(1)
ny = s(2)
gs = [1,1]
b = [0,0,nx-1, ny-1]
if (N_ELEMENTS(quint) EQ 0) then quint = 0
; Call for the xinteranimate tool to display
; the sequence of images.
;
xinteranimate, set=[nx, ny, nsteps], /SHOWLOAD, /CYCLE
for i=0, nsteps-1 do begin ;Each step
t = FLOAT(i) / FLOAT(nsteps-1) ;From 0.0 to 1.0
xt = x0 + (x1-x0) * t ;From 1st to 2nd
yt = y0 + (y1-y0) * t
xt1 = x1 + t * (x0-x1) ;From 2nd to 1st
yt1 = y1 + t * (y0-y1)
im1 = INTERPOLATE(i1, $
TRIGRID(x0,y0,xt1,tr, gs, b, QUINT=quint), $
TRIGRID(x0,y0,yt1,tr, gs, b, QUINT=quint))
im0 = INTERPOLATE(i0, $
TRIGRID(x1,y1,xt1,tr, gs, b, QUINT=quint), $
TRIGRID(x1,y1,yt1,tr, gs, b, QUINT=quint))
im = BYTE(t * im1 + (1.0-T) * im0)
xinteranimate, image=im, frame=i
endfor
end
;----------------------------------------------------------------------------
;
; Purpose: Main event handler.
;
pro d_morph_event, $
sEvent ; IN: event Structure
common morph_demo_common, cmd_button, frames_button, msg, lun, image_in, $
draw, draw_size, im_size, dwin, sx, nx, state, iindex, imlt, imrt, $
ncp, cpx, cpy, nimages, offsets, nframes
; Set to the morphing window.
;
WSET, dwin
; Brancjh accoridingly to the event.
;
case sEvent.id of
; Handle a mouse button event occuring in the viewing area.
;
frames_button: nframes = ([3,8,16,32])(sEvent.index)
draw: begin
; Returns if it is not a button press event.
;
if (sEvent.press NE 0) then RETURN
; Selecting an image
;
if (state LE 1) then begin
im = ((draw_size > !d.y_size) - sEvent.y) / $
sx * nx + sEvent.x / sx
iindex(state) = im
if (state EQ 0) then WIDGET_CONTROL, msg, $
SET_VALUE='Select other image' $
else begin
WIDGET_CONTROL, msg, SET_VALUE='Pick LEFT control point'
erase
for i=0,1 do begin
imrt = people_image(iindex(i), lun, offsets, $
LABEL=msg, /BW, REQUIRED=im_size)
TV, CONGRID(imrt, draw_size, draw_size), i*draw_size, 0
if (i EQ 0) then imlt = imrt
endfor
endelse
state = state + 1
ncp = 0
; Must be marking a control point (CP).
;
endif else begin
; Right image case.
;
rt = (sEvent.x GE draw_size)
; Scale to pixels.
;
x = (sEvent.x MOD draw_size) * im_size / $
draw_size
y = sEvent.y * im_size / draw_size
; If not the proper image, toss it.
;
if (rt NE (ncp AND 1)) then RETURN
; Mark the control point.
;
PLOTS, sEvent.x, sEvent.y, /DEVICE, $
; COLOR=!D.N_COLORS-1, PSYM=2
COLOR=!D.TABLE_SIZE-1, PSYM=2
empty
; First control point, else it is the second.
;
if ncp EQ 0 then begin
cpx = x
cpy = y
endif else begin
cpx = [cpx, x]
cpy = [cpy, y]
endelse
ncp = ncp + 1
; Refreash the message text.
;
WIDGET_CONTROL, msg, SET_VALUE= $
'Mark the ' + (['LEFT','RIGHT'])(ncp and 1) + ' image.'
if (!Version.Os NE 'MacOS') then $
TVCRS, sEvent.x - (2*rt-1) * draw_size, sEvent.y, /DEVICE $
else TVCRS, 1
endelse
endcase ; of draw
cmd_button: begin
; Branch to the approriate command button event.
;
case sEvent.value of
; Quit this application.
;
'Done': begin
if (image_in EQ 0) then FREE_LUN, lun
WIDGET_CONTROL, sEvent.top, /DESTROY
endcase ; of Done
'Help': begin
XDISPLAYFILE, GROUP=sEvent.top, $
DONE_BUTTON='Done', $
WIDTH=55, HEIGHT=14, $
TITLE='Morph Demo Help', TEXT= [ $
"Morphing is the gradual and continuous changing of ", $
"one image to another. This demonstration shows", $
"IDL's built-in irregular gridding, interpolation", $
"and image processing capabilities by changing", $
"one person's face to another.", $
" ", $
"To run this demo, select two images with the same", $
"general orientation. Then alternately mark control", $
"points on the same feature in each image.", $
"For example, the tip of the nose, corners of the", $
"lips, pupils of the eyes, and top of the head are", $
"readily distinguished features of human faces.",$
" More control points give better results.", $
" ", $
"When all points are marked, press the 'Go' button", $
"to morph between the images. You can experiment", $
"by adding OR removing control points, and", $
"stop and restart the animatation."]
endcase ; of Help
; Remove the previous control points.
;
'Delete CP': begin
; Return under certain conditions.
;
if (state LE 1) then RETURN
if (ncp LE 0) then RETURN
; Verify the validity of this event and handle it.
;
ncp = (ncp + (ncp and 1)) - 2
; If valid, set the control points.
;
if (ncp gt 0) then begin
cpx = cpx(0:ncp-1)
cpy = cpy(0:ncp-1)
endif
TV, CONGRID(imlt, draw_size, draw_size), 0, 0
TV, CONGRID(imrt, draw_size, draw_size), draw_size, 0
for i=0, ncp-1 do $
PLOTS, cpx(i) * draw_size / $
im_size + (i and 1) * draw_size, $
cpy(i) * draw_size / im_size, /DEVICE, $
; PSYM=2, COLOR=!D.N_COLORS-1
PSYM=2, COLOR=!D.TABLE_SIZE-1
WIDGET_CONTROL, msg, SET_VALUE= 'Mark the left image.'
endcase ; of Delete CP (control points)
; Restart the whole process.
;
'Restart': begin
ERASE
ncp = 0 ; number o fcontrol points.
if (image_in) then begin
TV, CONGRID(imlt, draw_size, draw_size), 0, 0
TV, CONGRID(imrt, draw_size, draw_size), draw_size, 0
endif else begin
TV, people_image(nimages, lun, offsets, LABEL=msg, /BW)
state = 0
endelse
endcase ; of Restart
; Start the animation sequence.
;
'Go' : begin
; Show the hourglass during the processing of the event.
;
WIDGET_CONTROL, sEvent.top, /HOURGLASS
; Return if the number of control points is less
; than 2 or the xinteranimate tool is already running.
;
if (ncp LT 2) then RETURN
if (XREGISTERED("XInterAnimate")) then RETURN
i2 = indgen(ncp/2) * 2 ;Alternate CPs
i1 = im_size -1
x0 = [cpx(i2), 0, i1, i1, 0] ;Add corners to CPs
x1 = [cpx(i2+1), 0, i1, i1, 0]
y0 = [cpy(i2), 0, 0, i1, i1]
y1 = [cpy(i2+1), 0, 0, i1, i1]
morph, imlt, imrt, x0, y0, x1, y1, nframes
xinteranimate, 40, group = sEvent.top
endcase ; of Go
endcase ; of sEvent.value
endcase ; of cmd_button
else: i2=0 ; Dummy statement.
endcase ; of sEvent.id
end
;-----------------------------------------------------------------
;
; PURPOSE : Cleanup procedure. Restore colortable.
;
pro morphCleanup, wTopBase
WIDGET_CONTROL, wTopBase, GET_UVALUE=sState, /NO_COPY
if (WIDGET_INFO(sState.group, /VALID_ID)) then begin
WIDGET_CONTROL, sState.group, SENSITIVE=1
endif
; Restore the color table.
;
TVLCT, sState.colorTable
imlt = 0 & imrt = 0 ;Clean up images
end ; of morphCleanup
;----------------------------------------------------------------------------
;
; Purpose: Main procedure. This application aplies mophing of 2 images.
;
pro d_morph, $
GROUP=Group, $ ; IN: (opt) group leader identifier
im0, $ ; IN: first image
im1, $ ; IN: second image
USE_CURRENT=use_current, $ ; IN: (opt) use files in current directory
FROM_PEOPLE=from_people ; IN: (opt) indicate for use of people demo.
;+
; Demo for morphing. If im0 and im1 are supplied, they are the two
; images to morph. If not supplied, the people.dat file is read and
; the user selects two faces to morph.
; USE_CURRENT = true to read from files in current directory.
;-
common morph_demo_common
nframes = 8
if N_ELEMENTS(group) eq 0 then group = 0L
if (group ne 0) then WIDGET_CONTROL, group, SENSITIVE=0
; Get the current color vectors to restore
; when this application is exited.
;
TVLCT, savedR, savedG, savedB, /GET
; Build color table from color vectors
;
colorTable = [[savedR],[savedG],[savedB]]
; Loads people demo , the people images, etc...
;
if (N_ELEMENTS(im_size) EQ 0 and KEYWORD_SET(from_people) EQ 0) then begin
if 0 then d_people ;This makes sure we get .sav files right
resolve_routine, 'd_people'
endif
; Have only one instance of morph_demo running.
;
if (xregistered("d_morph")) then return
im_size = 256
image_in = N_ELEMENTS(im0) gt 2
; Initilize the image size and the size of the drawing area.
;
if (image_in) then im_size = (SIZE(im0))(1) ;We're passed images
draw_size = 256 > im_size ;Size of drawable
; Initialize other working variables and arrays.
;
state = 0
ncp = 0 ; number of control points.
iindex = INTARR(2)
; Create the widgets, starting with the top level base.
;
Base = WIDGET_BASE(Title='Morphing', /ROW)
; Create the left base containing the control buttons
; and the message text.
;
left = WIDGET_BASE(base, /COLUMN)
cmd_button = CW_BGROUP(left, /NO_REL, $
/RETURN_NAME, /COL, /FRAME, $
['Done', 'Help', 'Restart', 'Delete CP', 'Go'])
frames_button = WIDGET_DROPLIST(left, VALUE= ['3', '8', '16', '32'], $
/FRAME, TITLE='Frames')
WIDGET_CONTROL, frames_button, SET_DROPLIST_SELECT=1
msg = WIDGET_TEXT(left, XSIZE=20, YSIZE=1, $
VALUE=(['Select two images', $
'Mark the left image.'])(image_in))
siz = [draw_size*2, draw_size]
DEVICE, get_screen=x
if (NOT image_in) then siz = siz > ([384, 512])(x(0) gt 640)
; Create the drawing area.
;
draw = WIDGET_DRAW(base, xsize=siz(0), ysize=siz(1), /BUTTON_EVENTS)
; Realize the widgets.
;
WIDGET_CONTROL, base, /REALIZE
WIDGET_CONTROL, draw, GET_VALUE=dwin
WSET, dwin
; Load the grey scale color table.
;
loadct, 0
; Display the initial images.
;
if (image_in EQ 0) then begin ;Initial display
read_people_index, names, offsets, USE_CURRENT=use_current
nimages = N_ELEMENTS(names)
nx = SQRT(nimages) ;# of images across
if (nx NE fix(nx)) then nx = nx + 1
nx = fix(nx)
sx = min(siz) / nx ;Size of image
filename = 'people.jpg'
if (KEYWORD_SET(use_current) EQ 0) then $
;filename = demopath(filename, subdir='images')
filename = filepath(filename, SUBDIR=['examples','data'])
OPENR, lun, /GET, filename, /STREAM
TV, people_image(nimages, lun, offsets, $
LABEL=msg, /BW, REQUIRED=min(siz))
; Images passed in case.
;
endif else begin ;Images passed in
state=2
imlt = im0
imrt = im1
TV, CONGRID(imlt, draw_size, draw_size), 0
TV, CONGRID(imrt, draw_size, draw_size), 1
endelse
; Create the state structure.
;
sState = { $
ColorTable:colorTable, $
Group: group $
}
WIDGET_CONTROL, Base, SET_UVALUE=sState, /NO_COPY
Xmanager, 'd_morph', base, GROUP_LEADER=group, $ ; , /NO_BLOCK
CLEANUP='morphCleanup'
end